package com.ddxz.tool.web.component;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.ddxz.tool.core.convert.StringUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 朱宗刚
 * @version 1.0.0
 * @description com.casic.exchange.com.casic.common.tools.component.CasicConfigure
 * @date 2020/2/28
 */

@Slf4j
@Configuration
@EnableConfigurationProperties(DdxzProperties.class)
@ConditionalOnProperty(prefix = "ddxz", value = "enabled", matchIfMissing = true)
@Import({Swagger2DocumentationConfiguration.class})
public class DdxzConfigure {
    private final DdxzProperties properties;

    public DdxzConfigure(DdxzProperties properties) {
        this.properties = properties;
    }

    /**
     * 使用该方式解析客户端传输的数据时，会因为客户端使用类型的不同而导致错误。
     * fastjson在该情况下会替换spring原有的参数转换器，一旦发生问题就回抛出异常。
     * 使用正确的使用方式见
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(HttpMessageConverters.class)
    public HttpMessageConverters httpMessageConverters() {
        log.debug("begin fastjson configure.");
        FastJsonConfig config = new FastJsonConfig();
        config.setCharset(StandardCharsets.UTF_8);
        config.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        config.setSerializerFeatures(SerializerFeature.PrettyFormat);
        if(properties.getFastjson().getDisplayNull()) {
            config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
        } else {
            config.setSerializerFeatures(SerializerFeature.IgnoreNonFieldGetter);
        }
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        // 仅application/json类型的请求使用该参数转换器
        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON));
        converter.setFastJsonConfig(config);

        return new HttpMessageConverters(converter);
    }

    @Bean
    @ConditionalOnMissingBean(DdxzLogAspect.class)
    public DdxzLogAspect casicLogAspect() {
        return new DdxzLogAspect(properties.getIgnoreLogClass());
    }

    @Bean
    @ConditionalOnMissingBean(DdxzWebMvcConfig.class)
    public DdxzWebMvcConfig casicWebMvcConfig() {
        return new DdxzWebMvcConfig();
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), properties.getDruid().getPath());
        if(!StringUtil.isEmpty(properties.getDruid().getAllow())) {
            bean.addInitParameter("allow", properties.getDruid().getAllow());
        }

        if(!StringUtil.isEmpty(properties.getDruid().getDeny())) {
            bean.addInitParameter("deny", properties.getDruid().getDeny());
        }
        bean.addInitParameter("loginUsername", properties.getDruid().getUserName());
        bean.addInitParameter("loginPassword", properties.getDruid().getPassword());
        bean.addInitParameter("resetEnable", properties.getDruid().getEnableReset().toString());
        return bean;
    }

    @Bean
    public FilterRegistrationBean statFilter(){
        FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(new WebStatFilter());
        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico," + properties.getDruid().getPath());
        return filterRegistrationBean;
    }

    @Bean
    public DdxzGlobalException globalException() {
        return new DdxzGlobalException();
    }

    @Bean
    @ConditionalOnMissingBean(Docket.class)
    public Docket docket() {
        RequestParameterBuilder builder = new RequestParameterBuilder();
        List<RequestParameter> parameterList = new ArrayList<>();
        builder.name("Authorzation")
                .description("JWT令牌")
                .in(ParameterType.HEADER)
                .required(false);
//        parameterBuilder.name("Authorization").description("令牌").modelRef(new ModelRef("string"))
//                .parameterType("header").required(false).build();
        parameterList.add(builder.build());

        return new Docket(DocumentationType.SWAGGER_2)
                .host(properties.getSwagger().getHost())
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any()).build()
                .globalRequestParameters(parameterList)
                .apiInfo(getApiInfo());
    }

    private ApiInfo getApiInfo() {
        return new ApiInfoBuilder()
                .contact(new Contact(properties.getSwagger().getCompany(), properties.getSwagger().getAddress(), properties.getSwagger().getEmail()))
                .title(properties.getSwagger().getTitle())
                .description(properties.getSwagger().getDesc())
                .version(properties.getSwagger().getVersion())
                .build();
    }
}
